<template>
  <div
    class="upload-drag"
    @dragleave="dragleave($event)"
    @dragenter="dragenter($event)"
    @dragover="dragover($event)"
    @drop="drop($event)"
    :class="{ dragOver: dragBoxStyle }"
  >
    <div class="upload-logo">
      <UploadFilled class="upload-icon" />
      <div class="upload-tip-text">将目录或多个文件拖拽到此处进行扫描</div>
    </div>
    <div class="upload-tip upload-tip-text">支持的文件类型：无限制</div>
    <div class="upload-tip upload-tip-text">
      每个文件允许的最大尺寸：{{ fileMaxSize }}
    </div>
  </div>

  <div class="el-button el-button--primary file-input">
    选择文件
    <input type="file" multiple @change="selectFile($event)" />
  </div>
  <div class="el-button el-button--primary file-input">
    选择文件夹
    <input
      type="file"
      multiple
      webkitdirectory
      mozdirectory
      odirectory
      @change="selectFile"
    />
  </div>
  <el-popconfirm title="确定清空文件列表吗？" @confirm="clearFiles">
    <template #reference>
      <el-button type="warning">清空文件列表</el-button>
    </template>
  </el-popconfirm>

  <el-table
    class="table"
    :header-cell-style="{ 'text-align': 'center' }"
    header-align="center"
    :data="fileList"
    border
  >
    <template #empty>
      <el-empty :image-size="100" description="No Data" />
    </template>
    <el-table-column prop="name" label="文件名" />
    <el-table-column prop="type" label="类型" align="center" />
    <el-table-column prop="size" label="大小" align="center">
      <template #default="{ row }"> {{ formatFileSize(row.size) }} </template>
    </el-table-column>
    <el-table-column prop="status" label="状态" align="center">
      <template #default="{ row }">
        <el-tag v-if="row.status === 1" effect="plain"> </el-tag>
        <el-progress
          v-else-if="row.status === 2"
          :percentage="row.process"
          :status="row.uploaded"
        />
        <el-tag v-else-if="row.status === 0" type="success" effect="plain">
          已上传
        </el-tag>
      </template>
    </el-table-column>
    <el-table-column
      fixed="right"
      label="操作"
      align="center"
      min-width="100px"
    >
      <template #default="scope">
        <el-button
          type="warning"
          :icon="Failed"
          circle
          title="取消上传"
          @click="cancelUpload(scope.row)"
        />
        <el-button
          style="margin-left: 10px"
          type="danger"
          :icon="Delete"
          circle
          title="删除"
          @click="deleteFile(scope.row)"
        />
      </template>
    </el-table-column>
  </el-table>

  <el-tag class="tag" type="info" effect="plain"
    >文件数量：{{ fileList.length }}</el-tag
  >
  <el-tag class="tag" type="success" effect="plain"
    >成功上传：{{ uploadedNum }}</el-tag
  >
  <el-tag class="tag" type="info" effect="plain">
    总大小：{{ formatFileSize(fileTotalSize) }}
  </el-tag>

  <el-button
    class="upload-btn"
    type="primary"
    @click="uploadMultipleFiles(fileList)"
    >开始上传</el-button
  >
</template>

<script setup>
import { ElMessage } from 'element-plus'
import { formatFileSize, fileSizeExceeds } from '@/utils'
import { UploadFilled, Delete, Failed } from '@element-plus/icons-vue'
import { ref, computed } from 'vue'
import { useUploadFile, fileUploadConfig } from '@/hooks/uploadHook'
const { fileMaxSize } = fileUploadConfig
const dragBoxStyle = ref(false)
const fileList = ref([])
const fileTotalSize = computed(() => {
  return fileList.value.reduce((totalSize, { size }) => totalSize + size, 0)
})
const uploadedNum = computed(() => {
  return fileList.value.filter(({ status }) => status === 0).length
})

const dragleave = (e) => {
  e.preventDefault()
  if (dragBoxStyle.value) {
    dragBoxStyle.value = false
  }
}
const dragenter = (e) => {
  e.preventDefault()
  if (!dragBoxStyle.value) {
    dragBoxStyle.value = true
  }
}
const dragover = (e) => {
  e.preventDefault()
}
const drop = async (e) => {
  e.preventDefault()
  dragBoxStyle.value = false
  const fileEntries = [...(await getFilesEntry(e.dataTransfer.items))]
  filesEntry2File(fileEntries)
}

// 拖拽选择文件
const filesEntry2File = (fileEntries) => {
  const filenameRegex = /([^/\\]+)\.([a-zA-Z0-9]+)$/
  for (const entry of fileEntries) {
    const temp = entry.name.match(filenameRegex) || ['', entry.name]
    entry.file((f) => {
      if (!fileSizeExceeds(f, fileMaxSize)) {
        const file = {
          name: temp[1],
          type: temp[2],
          size: f.size,
          status: 1,
          process: 0,
          uploaded: '',
          fileObj: f
        }
        fileList.value.push(file)
      } else {
        ElMessage.warning(`上传文件大小超过最大允许尺寸：${fileMaxSize}`)
      }
    })
  }
}
const getFilesEntry = async (data) => {
  const fileEntries = []
  for (const item of data) {
    const entry = item.webkitGetAsEntry()
    if (entry) {
      if (entry.isDirectory) {
        const directoryFiles = await getAllFileEntry(entry)
        fileEntries.push(...directoryFiles)
      } else if (entry.isFile) {
        fileEntries.push(entry)
      }
    }
  }
  return fileEntries
}
const getAllFileEntry = async (entry) => {
  const fileEntries = []
  if (entry.isDirectory) {
    const reader = entry.createReader()
    const entries = await readEntries(reader)
    for (const item of entries) {
      if (item.isDirectory) {
        const subDirectoryFiles = await getAllFileEntry(item)
        fileEntries.push(...subDirectoryFiles)
      } else if (item.isFile) {
        fileEntries.push(item)
      }
    }
  }
  return fileEntries
}
const readEntries = (reader) => {
  return new Promise((resolve) => {
    reader.readEntries((entries) => {
      resolve(entries)
    })
  })
}

// 选择文件/文件夹
const selectFile = (e) => {
  e.preventDefault()
  const filenameRegex = /([^/\\]+)\.([a-zA-Z0-9]+)$/
  for (const item of e.target.files) {
    if (fileSizeExceeds(item, fileMaxSize)) {
      ElMessage.warning(`
      文件${item.name}大小超过最大允许尺寸：${fileMaxSize}
      `)
      continue
    }
    const temp = item.name.match(filenameRegex) || ['', item.name]
    fileList.value.push({
      name: temp[1],
      size: item.size,
      type: temp[2],
      status: 1,
      process: 0,
      uploaded: '',
      fileObj: item
    })
  }
}

// 清空文件列表
const clearFiles = () => {
  if (fileList.value.length < 0) return
  fileList.value = []
}

// 删除文件列表某个文件
const deleteFile = (row) => {
  fileList.value = fileList.value.filter((item) => item.name !== row.name)
}

/*
 * 文件上传
 * */
const { uploadMultipleFiles, cancelUpload } = useUploadFile(uploadedNum)
</script>
<style lang="scss">
.dragOver {
  // 拖拽到指定区域样式
  border: 1px dashed rgb(224, 227, 233) !important;
  background-color: rgba(224, 227, 233, 0.5) !important;
}
.el-table thead {
  color: rgba(0, 0, 0, 0.7);
}
.upload-drag {
  user-select: none;
  height: 200px;
  display: flex;
  align-content: center;
  justify-content: center;
  flex-wrap: wrap;
  padding: var(--el-upload-dragger-padding-horizontal)
    var(--el-upload-dragger-padding-vertical);
  background-color: var(--el-fill-color-blank);
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  box-sizing: border-box;
  text-align: center;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  margin-bottom: 15px;

  .upload-logo {
    width: 100%;
    height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
    .upload-icon {
      margin-right: 10px;
      width: 50px;
      color: var(--el-text-color-placeholder);
    }
  }
  .upload-tip {
    width: 100%;
    height: 30px;
  }
  .upload-tip-text {
    color: var(--el-text-color-placeholder);
    line-height: 50px;
    text-align: center;
    font-size: 14px;
  }
}
.file-input {
  position: relative;
  display: inline-block;
  padding: 8px 15px;
  overflow: hidden;
  text-decoration: none;
  text-indent: 0;

  input {
    height: 100%;
    width: 100%;
    position: absolute;
    color: transparent;
    right: 0;
    top: 0;
    opacity: 0;
  }
}
.cancel-btn {
  &:hover {
    color: orange;
  }
}
.table {
  margin: 15px 0;
  user-select: none;
}
.tag {
  margin-right: 5px;
  user-select: none;
}
.upload-btn {
  display: block;
  margin: 15px 0;
}
</style>
